package com.lzw.DailyAudit.service.dateAggregation_02.DailyAudit.service.dateAggregation_02;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.hooya.fa.eu.biz.DailyAudit.entity.DailyAuditStatus;
import com.hooya.fa.eu.biz.DailyAudit.entity.StkOrigDataCollect;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.ZyDataDTO;
import com.hooya.fa.eu.biz.DailyAudit.mapper.*;
import com.hooya.integrated.common.util.times.DateExtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
@DS("fa_eu_daily")
public class Insert_ZY {

    @Autowired
    private DailyTempZyjlMapper dailyTempZyjlMapper;

    @Autowired
    private DailyCostHisMapper dailyCostHisMapper;

    @Autowired
    private DailyCostLastMapper dailyCostLastMapper;

    @Autowired
    private DailyMetaStkCustomsMapper mataStkCustomsMapper;

    @Autowired
    private CommonService commonService;

	@Autowired
	private DailyAuditStatusMapper statusMapper;

	@Transactional
	public void insert_zy(String currentDate) {
		try {

			String name = "insertZy-02";
			DailyAuditStatus dailyAuditStatus = statusMapper.selectStatus(name, currentDate);
			if(dailyAuditStatus != null && dailyAuditStatus.getFlag() == 1){
				log.info("{} - 该方法已执行，进行跳过！",name);
				return;
			}

			log.info("开始执行转运数据插入任务，开始日期：{}", currentDate);

			String curMonthFirstDay = DateExtUtil.getCurMonthFirstDay(LocalDate.parse(currentDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")));

			// 获取入仓数据和出仓数据
            List<ZyDataDTO> inData = dailyTempZyjlMapper.getZyInData(currentDate); // fa_eu.temp_zyjl a, fa_eu.meta_warehouse b , fa_eu.meta_warehouse c
            List<ZyDataDTO> outData = dailyTempZyjlMapper.getZyOutData(currentDate); // fa_eu.temp_zyjl a, fa_eu.meta_warehouse b , fa_eu.meta_warehouse c

            // 合并入仓和出仓数据
            List<ZyDataDTO> inoutData = new ArrayList<>(inData);
            inoutData.addAll(outData);

            // 获取海运费数据
            List<ZyDataDTO> hisOceanFee = dailyCostHisMapper.getHisOceanFeeData(currentDate); // fa_eu.temp_zyjl  rxh_europe.cost_his
            List<ZyDataDTO> lastOceanFee = dailyCostLastMapper.getLastOceanFeeData(); // rxh_europe.cost_last

            // 获取首次出现日期
            Map<String, List<ZyDataDTO>> FirstDataMap = dailyTempZyjlMapper.getZyFirstDay(curMonthFirstDay,currentDate) //fa_eu.temp_zyjl
                    .stream()
                    .sorted(Comparator.comparing(ZyDataDTO::getHtrq, Comparator.naturalOrder()))
                    .collect(Collectors.groupingBy(ZyDataDTO::getCpbh));

            // 获取首次日期出现的数据
            List<ZyDataDTO> firstDay = getFirstData(FirstDataMap);

            // 添加海运费信息
            List<ZyDataDTO> oceanFeeData = addOceanFee(hisOceanFee, lastOceanFee, firstDay);

            //构建海运数据的Map映射集合
            Map<String, List<ZyDataDTO>> oceanFeeDataMap = oceanFeeData.stream().collect(Collectors.groupingBy(ZyDataDTO::getCpbh));
            List<ZyDataDTO> mergeData = new ArrayList<>();
            for (ZyDataDTO mainItem : inoutData) {
                String key = mainItem.getCpbh();
                if (oceanFeeDataMap.containsKey(key)) {
                    List<ZyDataDTO> ZyDataDTOS = oceanFeeDataMap.get(key);
                    ZyDataDTOS.forEach(f -> {
                        ZyDataDTO newItem = new ZyDataDTO();
                        BeanUtils.copyProperties(mainItem, newItem);
                        newItem.setPrice(f.getPrice());
                        newItem.setOceanfee(f.getOceanfee());
                        newItem.setHtrq(f.getHtrq());
                        mergeData.add(newItem);
                    });
                } else {
                    mergeData.add(mainItem);
                }
            }

            List<ZyDataDTO> oceanFeeIsNullList = mergeData.stream().filter(f -> f.getOceanfee() == null).collect(Collectors.toList());

            if (!oceanFeeIsNullList.isEmpty()) {
                log.error("异常数据数量：{}， 异常数据为：{}", oceanFeeIsNullList.size(), oceanFeeIsNullList);
                throw new RuntimeException("海运费数据为空");
            }

            // 添加ID信息
            List<ZyDataDTO> mainData = addId(mergeData, currentDate);

            // 为数据添加索引 -- 可以用，用的前提是顺序一致,但是不保险
            for (int i = 0; i < mainData.size(); i++) {
                mainData.get(i).setIndex(i + "");
            }

            // 准备价格匹配数据
            List<ZyDataDTO> cutMainData = new ArrayList<>();
            for (ZyDataDTO data : mainData) {
                ZyDataDTO priceData = new ZyDataDTO();
                priceData.setSku(data.getCpbh());
                priceData.setInoutDate(data.getDate());
                priceData.setBelongs(data.getBelongs());
                priceData.setAbbrbelongs(data.getAbbrbelongs());
                priceData.setIndex(data.getIndex());
                cutMainData.add(priceData);
            }

            // 添加价格信息
            Map<String, List<ZyDataDTO>> priceDataMap = addPrice(cutMainData, "inoutdate");
            List<ZyDataDTO> withPriceData = priceDataMap.get("withPrice");
            List<ZyDataDTO> withoutPriceData = priceDataMap.get("withoutPrice");

            // 添加异常价格信息
            List<ZyDataDTO> abnormalPriceData = addAbnormalPrice(withoutPriceData, "inoutdate");

            List<ZyDataDTO> allPriceData = new ArrayList<>(withPriceData);
            allPriceData.addAll(abnormalPriceData);

            //构建海运数据的Map映射集合
            Map<String, List<ZyDataDTO>> allPriceDataMap = allPriceData.stream().collect(Collectors.groupingBy(f -> f.getSku() + "|" + f.getIndex()));
            List<ZyDataDTO> mergeData2 = new ArrayList<>();
            for (ZyDataDTO mainItem : mainData) {
                String key = mainItem.getCpbh() + "|" + mainItem.getIndex();
                if (allPriceDataMap.containsKey(key)) {
                    List<ZyDataDTO> ZyDataDTOS = allPriceDataMap.get(key);
                    ZyDataDTOS.forEach(f -> {
                        ZyDataDTO newItem = new ZyDataDTO();
                        BeanUtils.copyProperties(mainItem, newItem);
                        newItem.setInoutDate(f.getInoutDate());
                        newItem.setInvoicedate(f.getInvoicedate());
                        newItem.setCurrency(f.getCurrency());
                        newItem.setPrice(f.getPrice());
                        mergeData2.add(newItem);
                    });
                } else {
                    mergeData2.add(mainItem);
                }
            }

            mergeData2.forEach(f -> f.setExportprice(f.getPrice()));

            // 数据验证
            commonService.dataVerificationZy(mergeData2);

            // 转换为StkOrigdataCollect对象并插入
            List<StkOrigDataCollect> records = commonService.convertZyToStkOrigDataCollect(mergeData2);
            commonService.batchInsert(records); // fa_eu_daily.stk_origData_collect

			// 修改执行状态
			commonService.UpdateOrInsertStatus(dailyAuditStatus, name, currentDate);

			log.info("转运数据插入任务完成");
        } catch (Exception e) {
            log.error("转运数据插入任务失败", e);
            throw new RuntimeException("转运数据插入任务失败", e);
        }
    }

    private List<ZyDataDTO> getFirstData(Map<String, List<ZyDataDTO>> FirstDataMap) {
        // 取每组第一条记录
        Map<String, ZyDataDTO> first_day = new HashMap<>();
        for (String key : FirstDataMap.keySet()) {
            List<ZyDataDTO> group = FirstDataMap.get(key);
            if (!first_day.containsKey(key) && !group.isEmpty()) {
                first_day.put(key, group.get(0));
            }
        }

        return new ArrayList<>(first_day.values());
    }

    /**
     * 添加价格
     */
    private List<ZyDataDTO> addOceanFee(List<ZyDataDTO> hisPrice, List<ZyDataDTO> lastPrice, List<ZyDataDTO> firstDay) {
        // 构建历史价格映射，按sort字段排序并按cpbh分组，取每组第一条记录
        Map<String, List<ZyDataDTO>> withHisPriceMap = hisPrice.stream().sorted(Comparator.comparing(ZyDataDTO::getSort)) // 按sort字段升序排序
                .collect(Collectors.groupingBy(ZyDataDTO::getCpbh));// 按cpbh分组，保留第一个（排序后的第一个）

        //设置得到日期的第一个数据并设置参数
        List<ZyDataDTO> withHisPrice = getFirstData(withHisPriceMap).stream().peek(f -> {
            f.setPrice(f.getHisPrice());
            f.setOceanfee(f.getHisOceanfee());
        }).collect(Collectors.toList());

        //得到不重复的cpbh数据
        List<ZyDataDTO> withoutPriceData = mergeAndGetDoNotRepeatCpbh(firstDay, withHisPrice);

        Map<String, List<ZyDataDTO>> lastPriceMap = lastPrice.stream().collect(Collectors.groupingBy(ZyDataDTO::getCpbh));
        List<ZyDataDTO> addLastPrice = new ArrayList<>();
        for (ZyDataDTO mainItem : withoutPriceData) {
            String key = mainItem.getCpbh();
            if (lastPriceMap.containsKey(key)) {
                List<ZyDataDTO> zyDataDTOS = lastPriceMap.get(key);
                zyDataDTOS.forEach(f -> {
                    ZyDataDTO newItem = new ZyDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setLastPrice(f.getLastPrice());
                    newItem.setLastOceanfee(f.getLastOceanfee());
                    addLastPrice.add(newItem);
                });
            } else {
                addLastPrice.add(mainItem);
            }
        }
        addLastPrice.forEach(f -> {
            f.setPrice(f.getLastPrice());
            f.setOceanfee(f.getLastOceanfee());
        });

        return Stream.concat(withHisPrice.stream(), addLastPrice.stream())
                .collect(Collectors.toList());
    }

    // 合并并获取不重复的cpbh数据
    private static List<ZyDataDTO> mergeAndGetDoNotRepeatCpbh(List<ZyDataDTO> firstDay, List<ZyDataDTO> withHisPrice) {
        // 1. 合并 withHisPrice 和 firstDay 两个集合
        List<ZyDataDTO> combined = Stream.concat(withHisPrice.stream(), firstDay.stream())
                .collect(Collectors.toList());

        // 2. 统计每个 cpbh 在合并后的总出现次数
        Map<String, Long> cpbhCount = combined.stream()
                .map(ZyDataDTO::getCpbh)
                .collect(Collectors.groupingBy(
                        cpbh -> cpbh,  // 按 cpbh 分组
                        Collectors.counting()  // 统计每个分组的数量
                ));

        // 3. 筛选出仅出现一次的 cpbh 对应的记录（即两个集合中均不重复的记录）
        return combined.stream()
                .filter(dto -> cpbhCount.get(dto.getCpbh()) == 1)  // 只保留出现次数为1的记录
                .collect(Collectors.toList());
    }


    /**
     * 添加ID信息
     */
    private List<ZyDataDTO> addId(List<ZyDataDTO> data, String date) {
        List<ZyDataDTO> result = new ArrayList<>();

        for (ZyDataDTO item : data) {
            ZyDataDTO withId = new ZyDataDTO();
            BeanUtil.copyProperties(item, withId);

            // 构造ID字符串
            StringBuilder idString = new StringBuilder();
            idString.append(date)
                    .append(withId.getHthm() != null ? withId.getHthm() : "")
                    .append(withId.getFromcompany() != null ? withId.getFromcompany() : "")
                    .append(withId.getTocompany() != null ? withId.getTocompany() : "")
                    .append(withId.getFromcountry() != null ? withId.getFromcountry() : "")
                    .append(withId.getTocountry() != null ? withId.getTocountry() : "");

            // 计算MD5哈希
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] hashBytes = md.digest(idString.toString().getBytes(StandardCharsets.UTF_8));
                StringBuilder sb = new StringBuilder();
                for (byte b : hashBytes) {
                    sb.append(String.format("%02x", b));
                }
                withId.set_id(sb.toString());
            } catch (Exception e) {
                log.error("计算MD5哈希失败", e);
            }

            result.add(withId);
        }

        return result;
    }

    /**
     * 添加价格
     */
    private Map<String, List<ZyDataDTO>> addPrice(List<ZyDataDTO> cutMainData, String priceDate) {
        try {
            log.info("开始添加价格数据，价格日期: {}", priceDate);
            Map<String, List<ZyDataDTO>> result = new HashMap<>();

            List<ZyDataDTO> PriceData = mataStkCustomsMapper.getZyPriceData().stream().filter(f -> f.getPrice() != null).collect(Collectors.toList()); //fa_eu.meta_stk_customs

            Map<String, List<ZyDataDTO>> PriceDataMap = PriceData.stream().collect(Collectors.groupingBy(f -> f.getSku() + "|" + f.getPricebelongs()));

            //merge -->  mainData数据和plnPriceData数据
            List<ZyDataDTO> mergeData = new ArrayList<>();
            for (ZyDataDTO mainItem : cutMainData) {
                String key = mainItem.getSku() + "|" + mainItem.getAbbrbelongs();
                if (PriceDataMap.containsKey(key)) {
                    List<ZyDataDTO> zyDataDTOS = PriceDataMap.get(key);
                    zyDataDTOS.forEach(f -> {
                        ZyDataDTO newItem = new ZyDataDTO();
                        BeanUtils.copyProperties(mainItem, newItem);
                        newItem.setInvoicedate(f.getInvoicedate());
                        newItem.setCurrency(f.getCurrency());
                        newItem.setQty(f.getQty());
                        newItem.setPrice(f.getPrice());
                        newItem.setPricebelongs(f.getPricebelongs());
                        mergeData.add(newItem);
                    });
                } else {
                    mergeData.add(mainItem);
                }
            }

            List<ZyDataDTO> withPriceData = mergeData.stream().filter(f -> f.getPrice() != null).collect(Collectors.toList());

            if (priceDate.equals("inoutdate")) {
                withPriceData.forEach(f -> f.setDateDiffer(ChronoUnit.DAYS.between(LocalDate.parse(f.getInvoicedate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(f.getInoutDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")))));
            } else {
                withPriceData.forEach(f -> f.setDateDiffer(ChronoUnit.DAYS.between(LocalDate.parse(f.getInvoicedate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(priceDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")))));
            }

            //完成了 日期的天数差值计算
            withPriceData = calculateDateAndGetFirstData(withPriceData);

            List<String> withPriceDataIndexList = withPriceData.stream().map(ZyDataDTO::getIndex).collect(Collectors.toList());

            List<ZyDataDTO> withoutPriceData = cutMainData.stream().filter(f -> !withPriceDataIndexList.contains(f.getIndex())).collect(Collectors.toList());

            result.put("withPrice", withPriceData);
            result.put("withoutPrice", withoutPriceData);
            log.info("添加价格数据完成，有价格数据: {} 条，无价格数据: {} 条", withPriceData.size(), withoutPriceData.size());
            return result;
        } catch (Exception e) {
            log.error("添加价格数据失败", e);
            throw new RuntimeException("添加价格数据失败", e);
        }
    }

    /**
     * 计算日期差值并根据条件排序分组取得第一条记录
     */
    private static List<ZyDataDTO> calculateDateAndGetFirstData(List<ZyDataDTO> withPriceData) {
        withPriceData = withPriceData.stream().filter(f -> f.getDateDiffer() > 0).collect(Collectors.toList());

        // 按照日期差、数量、出口价格排序，然后按cpbh和index(sheetNumber+direction)分组，取每组第一条记录
        Map<String, List<ZyDataDTO>> groupedData = withPriceData.stream().sorted(Comparator.comparing(ZyDataDTO::getDateDiffer, Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(ZyDataDTO::getQty, Comparator.nullsLast(Comparator.reverseOrder())).thenComparing(ZyDataDTO::getPrice, Comparator.nullsLast(Comparator.reverseOrder()))).collect(Collectors.groupingBy(f -> f.getSku() + f.getInoutDate() + f.getIndex()));

        // 取每组第一条记录
        Map<String, ZyDataDTO> withPriceDataMap = new HashMap<>();
        for (String key : groupedData.keySet()) {
            List<ZyDataDTO> group = groupedData.get(key);
            if (!withPriceDataMap.containsKey(key) && !group.isEmpty()) {
                withPriceDataMap.put(key, group.get(0));
            }
        }

        withPriceData = new ArrayList<>(withPriceDataMap.values());
        return withPriceData;
    }

    /**
     * 添加异常价格
     */
    private List<ZyDataDTO> addAbnormalPrice(List<ZyDataDTO> withoutPriceData, String priceDate) {
        try {
            log.info("开始添加异常价格数据，价格日期: {}", priceDate);

            List<ZyDataDTO> PriceData = mataStkCustomsMapper.getZyPriceData().stream().filter(f -> f.getPrice() != null).collect(Collectors.toList()); // fa_eu.meta_stk_customs

            Map<String, List<ZyDataDTO>> PriceDataMap = PriceData.stream().collect(Collectors.groupingBy(ZyDataDTO::getSku));

            //merge -->  mainData数据和plnPriceData数据
            List<ZyDataDTO> mergeData = new ArrayList<>();
            for (ZyDataDTO mainItem : withoutPriceData) {
                String key = mainItem.getSku();
                if (PriceDataMap.containsKey(key)) {
                    List<ZyDataDTO> ZyDataDTOS = PriceDataMap.get(key);
                    ZyDataDTOS.forEach(f -> {
                        ZyDataDTO newItem = new ZyDataDTO();
                        BeanUtils.copyProperties(mainItem, newItem);
                        newItem.setInvoicedate(f.getInvoicedate());
                        newItem.setCurrency(f.getCurrency());
                        newItem.setQty(f.getQty());
                        newItem.setPrice(f.getPrice());
                        newItem.setPricebelongs(f.getPricebelongs());
                        mergeData.add(newItem);
                    });
                } else {
                    mergeData.add(mainItem);
                }
            }

            //去除价格为空的记录
            List<ZyDataDTO> abWithPriceData = mergeData.stream().filter(f -> f.getPrice() != null).collect(Collectors.toList());

            //计算differDate值
            if (priceDate.equals("inoutdate")) {
                abWithPriceData.forEach(f -> f.setDateDiffer(ChronoUnit.DAYS.between(LocalDate.parse(f.getInvoicedate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(f.getInoutDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")))));
            } else {
                abWithPriceData.forEach(f -> f.setDateDiffer(ChronoUnit.DAYS.between(LocalDate.parse(f.getInvoicedate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")), LocalDate.parse(priceDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")))));
            }

            //完成了 日期的天数差值计算
            abWithPriceData = calculateDateAndGetFirstData(abWithPriceData);

            log.info("添加异常价格数据完成，处理数据: {} 条", abWithPriceData.size());
            return abWithPriceData;
        } catch (Exception e) {
            log.error("添加异常价格数据失败", e);
            throw new RuntimeException("添加异常价格数据失败", e);
        }
    }


}